/**
 Signal and Slot for Java
 Copyright (C) 2003 Thia Yeo Ching (tycordinal@yahoo.co.uk)
 http://sourceforge.net/projects/javasignalslot/

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package org.arclib.signal;

import java.util.ArrayList;
import java.util.Iterator;


/**
 * Simple connection between a pair of signal and slot.
 * Note that signal and slot names never uniquely identify
 * any connection.
 *
 * This is simple and easy to use, and more resemble to
 * Qt's signal and slot model. Enjoy!
 * Take a look at how to make use of the concept by those
 * creative guys:
 * http://doc.trolltech.com/3.1/signalsandslots.html
 *
 * Author: Thia Yeo Ching, tycordinal@yahoo.co.uk
 * Date: Mar 26, 2003
 * Time: 2:40:38 AM
 */
public class SignalSlotMap
{
  // TODO: An index needs to be created using signalProvider as key
  // TODO: so to speed up the signal emitting process
  private static ArrayList connectionList_ = new ArrayList();

  /**
   * Establish a connection. No checking for duplication.
   * Use this if you want typesafe checking
   * @param signalProvider
   * @param signalName usually a constant of signalProvider class
   * @param slotProviderMethodPair create using SlotProviderMethodPair.create
   */
  public static synchronized void connect(ISignalProvider signalProvider, String signalName,
    SlotProviderMethodPair slotProviderMethodPair)
  {
    if (slotProviderMethodPair != null)
    {
      connectionList_.add(new SignalSlotPair(signalProvider, signalName, slotProviderMethodPair));
    }

  }


  /**
   * Send signal data to all interested slot providers,
   * The slot providers must finish execution quickly and
   * never run into infinite loop. Do not make any assumption of
   * the calling sequence to slot providers.
   *
   * @param signalProvider
   * @param signalName
   * @param signalData Use methods in PrimitiveWrapper to get wrapper for primitive types
   */
  public static synchronized void emit(ISignalProvider signalProvider, String signalName,
    Object signalData[])
  {
    Iterator it = connectionList_.iterator();
    while (it.hasNext())
    {
      SignalSlotPair ssp = (SignalSlotPair) it.next();
      if (ssp.matches(signalProvider, signalName))
      {
        ssp.invoke(signalData);
      }
    }
  }

  public static synchronized void emit(ISignalProvider signalProvider, String signalName,
    Object signalData)
  {
    emit(signalProvider, signalName, new Object[]{signalData});

  }

  /**
   * Use this if no extra signal object is needed
   * @param signalProvider
   * @param signalName
   */
  public static synchronized void emit(ISignalProvider signalProvider,
    String signalName)
  {
    emit(signalProvider, signalName, null);
  }

  public static synchronized void disconnect(ISignalProvider signalProvider, String signalName,
    SlotProviderMethodPair slotProviderMethodPair)
  {
    ArrayList toBeRemovedList = new ArrayList();

    Iterator it;
    it = connectionList_.iterator();
    while (it.hasNext())
    {
      SignalSlotPair ssp = (SignalSlotPair) it.next();
      if (ssp.matches(signalProvider, signalName, slotProviderMethodPair))
      {
        toBeRemovedList.add(ssp);
      }
    }

    removeConnections(toBeRemovedList);


  }

  /**
   * All connections with the signal gone
   * @param signalProvider
   * @param signalName
   */
  public static synchronized void disconnect(ISignalProvider signalProvider,
    String signalName)
  {
    ArrayList toBeRemovedList = new ArrayList();

    Iterator it;
    it = connectionList_.iterator();
    while (it.hasNext())
    {
      SignalSlotPair ssp = (SignalSlotPair) it.next();
      if (ssp.matches(signalProvider, signalName))
      {
        toBeRemovedList.add(ssp);
      }
    }

    removeConnections(toBeRemovedList);

  }

  /**
   * All connections between this pair of signal provider and slot provider gone
   * @param signalProvider
   * @param slotProvider
   */
  public static synchronized void disconnect(ISignalProvider signalProvider,
    ISlotProvider slotProvider)
  {
    ArrayList toBeRemovedList = new ArrayList();

    Iterator it;
    it = connectionList_.iterator();
    while (it.hasNext())
    {
      SignalSlotPair ssp = (SignalSlotPair) it.next();
      if (ssp.matches(signalProvider, slotProvider))
      {
        toBeRemovedList.add(ssp);
      }
    }

    removeConnections(toBeRemovedList);

  }

  /**
   * One of the slot of the slotProvider will not receive the signal
   * @param signalProvider
   */
  public static synchronized void disconnect(ISignalProvider signalProvider,
    SlotProviderMethodPair slotProviderMethodPair)
  {
    ArrayList toBeRemovedList = new ArrayList();

    Iterator it;
    it = connectionList_.iterator();
    while (it.hasNext())
    {
      SignalSlotPair ssp = (SignalSlotPair) it.next();
      if (ssp.matches(signalProvider, slotProviderMethodPair))
      {
        toBeRemovedList.add(ssp);
      }
    }

    removeConnections(toBeRemovedList);

  }

  /**
   * All connections from this signal provider gone
   * @param signalProvider
   */
  public static synchronized void disconnect(ISignalProvider signalProvider)
  {
    ArrayList toBeRemovedList = new ArrayList();

    Iterator it;
    it = connectionList_.iterator();
    while (it.hasNext())
    {
      SignalSlotPair ssp = (SignalSlotPair) it.next();
      if (ssp.matches(signalProvider))
      {
        toBeRemovedList.add(ssp);
      }
    }

    removeConnections(toBeRemovedList);

  }

  /**
   * All connection to this slot provider gone
   * @param slotProvider
   */
  public static synchronized void disconnect(ISlotProvider slotProvider)
  {
    ArrayList toBeRemovedList = new ArrayList();

    Iterator it;
    it = connectionList_.iterator();
    while (it.hasNext())
    {
      SignalSlotPair ssp = (SignalSlotPair) it.next();
      if (ssp.matches(slotProvider))
      {
        toBeRemovedList.add(ssp);
      }
    }

    removeConnections(toBeRemovedList);

  }

  private static void removeConnections(ArrayList toBeRemovedList)
  {
    Iterator it;
    it = toBeRemovedList.iterator();
    while (it.hasNext())
    {
      connectionList_.remove(it.next());
    }

    toBeRemovedList.clear();
  }



}

